﻿using System;
using System.Reflection;
using System.Configuration;
using Vbyte.DataSource.Cache;

namespace Vbyte.SharpOrm.Config
{
    /// <summary>
    /// 字段(属性)的子表关联配置
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
    public class ChildTableAttribute : Attribute
    {
        /// <summary>
        /// 新建一个子表关联映射实例(字段属性即子对象关联属性绑定)
        /// </summary>
        public ChildTableAttribute()
            : base()
        { }
        
        /// <summary>
        /// 新建一个子表关联映射实例
        /// </summary>
        /// <param name="dependencyProperties">依赖父级的属性集合，也即子表的选择条件。
        /// <para>如果子级对象的字段不一致，则字段定义格式为”父级属性名:子对象属性名“，否则指定一个属性名即可：如”属性名“。</para>
        /// </param>
        public ChildTableAttribute(string[] dependencyProperties)
        {
            if (dependencyProperties == null || dependencyProperties.Length < 1)
            {
                throw new System.Configuration.ConfigurationErrorsException("子级对象映射必须指定关联属性映射！");
            }
            DependencyProperties = dependencyProperties;
        }

        /// <summary>
        /// 获取或设置依赖父级属性的绑定集合
        /// </summary>
        public string[] DependencyProperties { get; set; }

        /// <summary>
        /// 继承父级对象的属性
        /// </summary>
        /// <param name="parent">父级对象</param>
        /// <param name="parentProperty">父级对象的数组属性对象</param>
        public void BindChildFromParent(object parent, PropertyInfo parentProperty)
        {
            if (parent == null || parentProperty == null) return;
            if (DependencyProperties == null || DependencyProperties.Length == 0)
            {
                DependencyProperties = new string[] { parentProperty.Name };
            }

            Type t = parent.GetType();
            string parentPropName, childPropName;
            string[] parentChildPropName = new string[1];
            if (parentProperty.PropertyType.IsArray)
            {
                object[] arrObject = parentProperty.GetGetMethod().Invoke(parent, null) as object[];
                Type childInstanceType = parentProperty.PropertyType.GetElementType();

                if (arrObject != null || arrObject.Length > 0)
                {
                    PropertyInfo pProperty, cProperty;
                    for (int i = 0, j = arrObject.Length; i < j; i++)
                    {
                        foreach (string pKey in DependencyProperties)
                        {
                            parentChildPropName = pKey.Split(':');
                            parentPropName = parentChildPropName[0];
                            childPropName = (parentChildPropName.Length > 1) ? parentChildPropName[1] : parentPropName;

                            pProperty = t.GetProperty(parentPropName);
                            cProperty = childInstanceType.GetProperty(childPropName);

                            if (pProperty == null || cProperty == null)
                            {
                                throw new ConfigurationErrorsException(String.Format("父级对象和子级对象属性关联配置错误：父属性名[{0}]或子属性名[{1}]不存在！{2}父对象：{3}{2}子对象：{4}",
                                    parentPropName, childPropName,
                                    Environment.NewLine,
                                    t.FullName, childInstanceType.FullName)
                                );
                            }
                            else
                            {
                                ReflectCache.SetProperty(childInstanceType, arrObject[i], cProperty, 
                                    ReflectCache.GetProperty(t, parent, pProperty));
                            }
                        }
                    }
                    //更新父级对象的相关属性的值
                    ReflectCache.SetProperty(t, parent, parentProperty, arrObject);
                }
            }
        }

    }

}
